/**
 * Copyright 2021 xpstem.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.xpstem.lelink.operation;

import com.xpstem.lelink.enums.Color;
import com.xpstem.lelink.enums.OpCode;
import com.xpstem.lelink.type.Data16;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class EV3UIOpFactory {

    public static final short CMD_DRAW_UPDATE = 0x00;
    public static final short CMD_DRAW_PIXEL = 0x02;
    public static final short CMD_DRAW_LINE = 0x03;
    public static final short CMD_DRAW_CIRCLE = 0x04;
    public static final short CMD_DRAW_TEXT = 0x05;

    private EV3UIOpFactory() { }

    /**
     * Automatically triggers a refreshes of the display.
     */
    public static EV3Operation opUIDrawUpdate() throws IOException {

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        LCEncoder.from(CMD_DRAW_UPDATE).lc0(outputStream);
        byte[] bytes = outputStream.toByteArray();

        EV3OperationPackage opPkg = new EV3OperationPackage( OpCode.UI_DRAW, bytes );
        return new EV3Operation(opPkg, "UI_DRAW_Update" );
    }

    /**
     * Enable drawing a single pixel.
     *
     * @param color (DATA8) Color – Specify either black or white, [0: White, 1: Black]
     * @param x (Data16) X0 – Specify X point, [0 - 177]
     * @param y (Data16) Y0 – Specify Y point, [0 - 127]
     */
    public static EV3Operation opUIDrawPixel(
            Color color, Data16 x, Data16 y) throws IOException {

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        LCEncoder.from(CMD_DRAW_PIXEL).lc0(outputStream);
        LCEncoder.from(color).lc0(outputStream);
        LCEncoder.from(x).lcx(outputStream);
        LCEncoder.from(y).lcx(outputStream);
        byte[] bytes = outputStream.toByteArray();

        EV3OperationPackage opPkg = new EV3OperationPackage( OpCode.UI_DRAW, bytes );
        return new EV3Operation( opPkg, "UI_DRAW_Pixel");
    }

    /**
     * Enable drawing a line between above coordinates
     *
     * @param color (DATA8) Color – Specify either black or white, [0: White, 1: Black]
     * @param x0 (Data16) X0 – Specify X start point, [0 - 177]
     * @param y0 (Data16) Y0 – Specify Y start point, [0 - 127]
     * @param x1 (Data16) X1 – Specify X end point
     * @param y1 (Data16) Y1 – Specify Y end point
     */
    public static EV3Operation opUIDrawLine(
            Color color, Data16 x0, Data16 y0, Data16 x1, Data16 y1) throws IOException {

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        LCEncoder.from(CMD_DRAW_LINE).lc0(outputStream);
        LCEncoder.from(color).lc0(outputStream);
        LCEncoder.from(x0).lcx(outputStream);
        LCEncoder.from(y0).lcx(outputStream);
        LCEncoder.from(x1).lcx(outputStream);
        LCEncoder.from(y1).lcx(outputStream);
        byte[] bytes = outputStream.toByteArray();

        EV3OperationPackage opPkg = new EV3OperationPackage( OpCode.UI_DRAW, bytes );
        return new EV3Operation( opPkg, "UI_DRAW_Line");
    }

    /**
     * Enable drawing a circle
     *
     * @param color (DATA8) Color – Specify either black or white, [0: White, 1: Black]
     * @param x (Data16) X0 – Specify X start point, [0 - 177]
     * @param y (Data16) Y0 – Specify Y start point, [0 - 127]
     * @param r (Data16) R – Radius for circle
     */
    public static EV3Operation opUIDrawCircle(
            Color color, Data16 x, Data16 y, Data16 r) throws IOException {

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        LCEncoder.from(CMD_DRAW_CIRCLE).lc0(outputStream);
        LCEncoder.from(color).lc0(outputStream);
        LCEncoder.from(x).lcx(outputStream);
        LCEncoder.from(y).lcx(outputStream);
        LCEncoder.from(r).lcx(outputStream);
        byte[] bytes = outputStream.toByteArray();

        EV3OperationPackage opPkg = new EV3OperationPackage( OpCode.UI_DRAW, bytes );
        return new EV3Operation( opPkg, "UI_DRAW_Circle");
    }

    /**
     * Enable displaying text
     *
     * @param color (DATA8) Color – Specify either black or white, [0: White, 1: Black]
     * @param x (Data16) X0 – Specify X start point, [0 - 177]
     * @param y (Data16) Y0 – Specify Y start point, [0 - 127]
     * @param text (Data8) STRING – First character in string to draw (Zero terminated)
     */
    public static EV3Operation opUIDrawText(
            Color color, Data16 x, Data16 y, String text) throws IOException {

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        LCEncoder.from(CMD_DRAW_TEXT).lc0(outputStream);
        LCEncoder.from(color).lc0(outputStream);
        LCEncoder.from(x).lcx(outputStream);
        LCEncoder.from(y).lcx(outputStream);
        LCEncoder.from(text).lcs(outputStream);
        byte[] bytes = outputStream.toByteArray();

        EV3OperationPackage opPkg = new EV3OperationPackage( OpCode.UI_DRAW, bytes );
        return new EV3Operation( opPkg, "UI_DRAW_Text");
    }

    /**
     * This function flushes user interface buffers.
     */
    public static EV3Operation opUIFlush() throws IOException {

        EV3OperationPackage opPkg = new EV3OperationPackage( OpCode.UI_FLUSH, null );
        return new EV3Operation( opPkg);
    }
}
